package config

import (
	"encoding/json"
	"io/ioutil"
	"net/http"

	"github.com/spf13/viper"
)

type options struct {
	viper   *viper.Viper
	autoEnv bool
}

// Option 配置
type Option interface {
	apply(*options)
}

type optionFunc func(*options)

func (f optionFunc) apply(o *options) {
	f(o)
}

// WithViper viper实例 默认viper
func WithViper(viper *viper.Viper) Option {
	return optionFunc(func(o *options) {
		o.viper = viper
	})
}

// WithAutoEnv 实时加载环境变量 默认true
func WithAutoEnv(autoEnv bool) Option {
	return optionFunc(func(o *options) {
		o.autoEnv = autoEnv
	})
}

// Client 客户端
type Client interface {
	// 获取viper
	Viper() *viper.Viper
	// 加载远端配置
	LoadRemote(url string) error
	// 加载文件配置
	LoadFile(name string) error
	// 默认值
	SetDefaults(data map[string]interface{}) error
}

type client struct {
	viper *viper.Viper
}

// New 新建实例
func New(opts ...Option) Client {
	options := options{
		viper:   viper.GetViper(),
		autoEnv: true,
	}

	for _, o := range opts {
		o.apply(&options)
	}
	if options.autoEnv {
		options.viper.AutomaticEnv()
	}
	return &client{
		viper: options.viper,
	}
}

// GetViper 获取当前viper
func (c *client) Viper() *viper.Viper {
	return c.viper
}

// LoadFile 加载文件配置
func (c *client) LoadFile(name string) error {
	c.viper.SetConfigName(name)
	c.viper.AddConfigPath("./config")
	c.viper.AddConfigPath("./configs")
	c.viper.AddConfigPath(".")
	return viper.ReadInConfig()
}

// LoadRemote 加载配置
func (c *client) LoadRemote(url string) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}

	body, _ := ioutil.ReadAll(resp.Body)
	data := map[string]string{}
	err = json.Unmarshal(body, &data)
	if err != nil {
		return err
	}

	for k, v := range data {
		c.viper.Set(k, v)
	}

	return nil
}

// SetDefault 默认配置
func (c *client) SetDefaults(data map[string]interface{}) error {
	for k, v := range data {
		c.viper.SetDefault(k, v)
	}

	return nil
}
